﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using DiscoveryLogic.Analytics.DataObjects.Networks;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.Analytics.DataObjects.Rules
{
    public class EntityRelationRule: RuleBase
    {
        #region props
        private SampleDataSourceType _SrcDataFrom;
        /// <summary>
        /// when use entity data set, 
        /// only set name and src entity type are used 
        /// 
        /// when use network entity, 
        /// network name, src entity type, and src key are used
        /// </summary>
        public SampleDataSourceType SrcDataFrom
        {
            get
            {
                return this._SrcDataFrom;
            }
            set
            {
                this._SrcDataFrom = value;
            }
        }

        private string _NetworkName;
        /// <summary></summary>
        public string NetworkName
        {
            get
            {
                return this._NetworkName;
            }
            set
            {
                this._NetworkName = value;
            }
        }

        private string _SrcKey;
        /// <summary></summary>
        public string SrcKey
        {
            get
            {
                return this._SrcKey;
            }
            set
            {
                this._SrcKey = value;
            }
        }

        private string _SrcEntitySetName;
        /// <summary></summary>
        public string SrcEntitySetName
        {
            get
            {
                return this._SrcEntitySetName;
            }
            set
            {
                this._SrcEntitySetName = value;
            }
        }

        private LinkType _LinkType;
        /// <summary></summary>
        public LinkType LinkType
        {
            get
            {
                return this._LinkType;
            }
            set
            {
                this._LinkType = value;
            }
        }

        private bool _Directional;
        /// <summary></summary>
        public bool Directional
        {
            get
            {
                return this._Directional;
            }
            set
            {
                this._Directional = value;
            }
        }

        private DataProviderType _DbProvider;
        /// <summary></summary>
        public DataProviderType DbProvider
        {
            get
            {
                return this._DbProvider;
            }
            set
            {
                this._DbProvider = value;
            }
        }

        private string _ConnStr;
        /// <summary></summary>
        public string ConnStr
        {
            get
            {
                return this._ConnStr;
            }
            set
            {
                this._ConnStr = value;
            }
        }

        private string _Sql;
        /// <summary></summary>
        public string Sql
        {
            get
            {
                return this._Sql;
            }
            set
            {
                this._Sql = value;
            }
        }

        #region input binding
        private Dictionary<string, string> _FieldNameMappings;
        /// <summary>
        /// field name from source data --> PropertyName
        /// </summary>
        public Dictionary<string, string> FieldNameMappings
        {
            get
            {
                return this._FieldNameMappings;
            }
            set
            {
                this._FieldNameMappings = value;
            }
        }
        #endregion

        #region sql binding
        private Dictionary<string, string> _SqlParameters;
        /// <summary>
        /// parameter name->prop name (src field)
        /// </summary>
        public Dictionary<string, string> SqlParameters
        {
            get
            {
                return this._SqlParameters;
            }
            set
            {
                this._SqlParameters = value;
            }
        }

        private Dictionary<string, SqlDbType> _parameterTypes;
        /// <summary>
        /// SqlParameterName (select from property names) --> SqlDbType
        /// </summary>
        public Dictionary<string, SqlDbType> ParameterTypes
        {
            get
            {
                return this._parameterTypes;
            }
            set
            {
                this._parameterTypes = value;
            }
        }

        //private Dictionary<string, string> _FieldTransformations;
        ///// <summary>
        ///// transform field value before bind to sql parameter
        ///// property name --> code
        ///// </summary>
        //public Dictionary<string, string> FieldTransformations
        //{
        //    get
        //    {
        //        return this._FieldTransformations;
        //    }
        //    set
        //    {
        //        this._FieldTransformations = value;
        //    }
        //}
        #endregion

        #region output binding
        private Dictionary<string, string> _OutputFieldNameMappings;
        /// <summary>
        /// output table column name --> target entity field name
        /// </summary>
        public Dictionary<string, string> OutputFieldNameMappings
        {
            get
            {
                return this._OutputFieldNameMappings;
            }
            set
            {
                this._OutputFieldNameMappings = value;
            }
        }

        #endregion

        #region entity link
        private Dictionary<string, ArgumentFieldBinding> _LinkCalcArgumentMappings;
        /// <summary>
        /// argument name --> ArgumentFieldBinding
        /// </summary>
        public Dictionary<string, ArgumentFieldBinding> LinkCalcArgumentMappings
        {
            get
            {
                return this._LinkCalcArgumentMappings;
            }
            set
            {
                this._LinkCalcArgumentMappings = value;
            }
        }

        private string _EntityLinkerName;
        /// <summary></summary>
        public string EntityLinkerName
        {
            get
            {
                return this._EntityLinkerName;
            }
            set
            {
                this._EntityLinkerName = value;
            }
        }

        private double _LinkDistanceThreshold;
        /// <summary>
        /// distance in the range of [0, infinite)
        /// the shorter the distance, more closely they are related
        /// </summary>
        public double LinkDistanceThreshold
        {
            get
            {
                return this._LinkDistanceThreshold;
            }
            set
            {
                this._LinkDistanceThreshold = value;
            }
        }

        private bool _AllowLoopBack;
        /// <summary>
        /// in the case of finding relation: Person -> Organization 
        /// found Person (a1) -> 3 Organizations (b1, b2, b3)
        /// when allow loop back, the exploration continues in the following steps
        /// 1. b1->(a1,a2,a3), b2->(a1,a4,a5), b3->(a1, a6)
        /// 2. if distance(a1->b1->a2) less then threshold, a2->(b1,b4)
        /// </summary>
        public bool AllowLoopBack
        {
            get
            {
                return this._AllowLoopBack;
            }
            set
            {
                this._AllowLoopBack = value;
            }
        }

        private double _HopDampFactor;
        /// <summary>
        /// this is used in distance filter
        /// suppose A->B->C->D with distance (0.1, 0.5, 0.6)
        /// when damp factor = 0.5, hop distance scale factor = 1/0.5=2
        /// distance from A to B = 0.1 * 2 * 1 = 0.2
        /// distance from A to C = 0.1 * 2 + 0.5 * 2 * 2 = 2.2
        /// distance from A to D = 0.1 * 2 * 1 + 0.5 * 2 * 2 + 0.6 * 2 * 3 = 5.8
        /// </summary>
        public double HopDampFactor
        {
            get
            {
                return this._HopDampFactor;
            }
            set
            {
                this._HopDampFactor = value;
            }
        }

        private string _TimeStampField;
        /// <summary></summary>
        public string TimeStampField
        {
            get
            {
                return this._TimeStampField;
            }
            set
            {
                this._TimeStampField = value;
            }
        }
        #endregion

        #endregion

        public EntityRelationRule(string ruleName, string iconPath, 
            EntityType srcEntityType, EntityType tgtEntityType, 
            string srcSetName)
            :base(ruleName, Rules.RuleType.Link,
            SetDataSourceType.XML, srcEntityType,
            tgtEntityType, iconPath)
        {
            _SrcDataFrom = SampleDataSourceType.EntityDataSet;
            _NetworkName = string.Empty;
            _SrcKey = string.Empty;
            _SrcEntitySetName = srcSetName;
            _Directional = false;
            _LinkType = Networks.LinkType.Citation;
            _DbProvider = DataProviderType.MSSQL;
            _ConnStr = string.Empty;
            _Sql = string.Empty;
            _FieldNameMappings=new Dictionary<string, string>();
            _SqlParameters=new Dictionary<string, string>();
            _parameterTypes=new Dictionary<string, SqlDbType>();
            _OutputFieldNameMappings=new Dictionary<string, string>();
            _EntityLinkerName = string.Empty;
            _LinkDistanceThreshold = 0;
            _LinkCalcArgumentMappings=new Dictionary<string, ArgumentFieldBinding>();
            _HopDampFactor = 0;
            _AllowLoopBack = false;
            _TimeStampField = string.Empty;
        }

        public EntityRelationRule(string ruleName, string iconPath, 
            string networkName, EntityType srcEntityType, 
            EntityType tgtEntityTYpe, string srcKey)
            : base(ruleName, Rules.RuleType.Link, SetDataSourceType.XML, 
            srcEntityType, tgtEntityTYpe, iconPath)
        {
            _SrcDataFrom = SampleDataSourceType.NetworkSelectedEntity;
            _NetworkName = networkName;
            _SrcKey = srcKey;
            _SrcEntitySetName = string.Empty;
            _Directional = false;
            _LinkType = Networks.LinkType.Citation;
            _DbProvider = DataProviderType.MSSQL;
            _ConnStr = string.Empty;
            _Sql = string.Empty;
            _FieldNameMappings = new Dictionary<string, string>();
            _SqlParameters = new Dictionary<string, string>();
            _parameterTypes = new Dictionary<string, SqlDbType>();
            _OutputFieldNameMappings = new Dictionary<string, string>();
            _EntityLinkerName = string.Empty;
            _LinkDistanceThreshold = 0;
            _LinkCalcArgumentMappings = new Dictionary<string, ArgumentFieldBinding>();
            _HopDampFactor = 0;
            _AllowLoopBack = false;
            _TimeStampField = string.Empty;
        }

        #region xml
        /// <summary>
        /// 
        /// </summary>
        /// <param name="xDoc"></param>
        /// <param name="relationRuleNode"></param>
        public override void Save(ref XmlDocument xDoc, 
            XmlNode relationRuleNode)
        {
            relationRuleNode.RemoveAll();
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "RuleName", this.RuleName);
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "RuleType",this.RuleType.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "IconPath",this.IconPath);

            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "SrcDataFormat",this.SrcDataFormat.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode,"SrcDataFrom",this.SrcDataFrom.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "NetworkName", this.NetworkName);
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "SrcEntityType", this.SrcEntityType.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "SrcKey", this.SrcKey);
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "SrcSetName",this.SrcEntitySetName);
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "Directional", this.Directional.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "LinkType",this.LinkType.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "TgtEntityType", this.TgtEntityType.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "DbProvider", this.DbProvider.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "ConnStr", this.ConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "Sql", this.Sql);

            if (this.FieldNameMappings != null && this.FieldNameMappings.Count > 0)
            {
                XmlNode inputMappingNodes = XmlDataUtil.AddElement(ref xDoc, relationRuleNode, "InputMappings");
                foreach (string propName in this.FieldNameMappings.Keys)
                {
                    XmlNode inputMappingNode = XmlDataUtil.AddElement(ref xDoc, inputMappingNodes, "InputMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc, inputMappingNode, "SrcField", this.FieldNameMappings[propName]);
                    XmlDataUtil.UpdateAttribute(ref xDoc, inputMappingNode, "PropName", propName);
                }
            }

            if (this.SqlParameters != null && this.SqlParameters.Count > 0)
            {
                XmlNode parameterNodes = XmlDataUtil.AddElement(ref xDoc, relationRuleNode, "SqlParameters");
                foreach (string propName in this.SqlParameters.Keys)
                {
                    XmlNode parameterNode = XmlDataUtil.AddElement(ref xDoc, parameterNodes, "SqlParameter");
                    XmlDataUtil.UpdateAttribute(ref xDoc, parameterNode, "PropertyName", propName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, parameterNode, "ParameterName", this.SqlParameters[propName]);
                }
            }

            if (this.ParameterTypes != null && this.ParameterTypes.Count > 0)
            {
                XmlNode sqlParamNodes = XmlDataUtil.AddElement(ref xDoc, relationRuleNode, "ParameterTypes");
                foreach (string paramName in this.ParameterTypes.Keys)
                {
                    XmlNode paramNode = XmlDataUtil.AddElement(ref xDoc, sqlParamNodes, "InputParameter");
                    XmlDataUtil.UpdateAttribute(ref xDoc, paramNode, "ParameterName", paramName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, paramNode, "DataType", this.ParameterTypes[paramName].ToString());
                }
            }

            if (this.OutputFieldNameMappings != null && this.OutputFieldNameMappings.Count > 0)
            {
                XmlNode outputMappingNodes = XmlDataUtil.AddElement(ref xDoc, relationRuleNode, "OutputMappings");
                foreach (string colName in this.OutputFieldNameMappings.Keys)
                {
                    XmlNode outputMappingNode = XmlDataUtil.AddElement(ref xDoc, outputMappingNodes, "OutputMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc, outputMappingNode, "ColName", colName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, outputMappingNode, "TgtField", this.OutputFieldNameMappings[colName]);
                }
            }

            if (this.LinkCalcArgumentMappings != null && this.LinkCalcArgumentMappings.Count > 0)
            {
                XmlNode argMappingNodes = XmlDataUtil.AddElement(ref xDoc, relationRuleNode, "LinkCalcArgMappings");
                foreach (string argName in this.LinkCalcArgumentMappings.Keys)
                {
                    XmlNode argMappingNode = XmlDataUtil.AddElement(ref xDoc, argMappingNodes, "LinkCalcArgMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc, argMappingNode, "ArgName", argName);
                    ArgumentFieldBinding argBinding = this.LinkCalcArgumentMappings[argName];
                    XmlDataUtil.UpdateAttribute(ref xDoc, argMappingNode, "FieldName", argBinding.PropertyName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, argMappingNode, "FromSrcEntity", argBinding.FromSrcEntity.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, argMappingNode, "FromTgtEntity", argBinding.FromTgtEntity.ToString());
                }
            }

            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "EntityLinkerName", this.EntityLinkerName);
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "LinkDistanceThreshold", this.LinkDistanceThreshold.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "AllowLoopBack", this.AllowLoopBack.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "HopDampFactor", this.HopDampFactor.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, relationRuleNode, "TimeStampField", this.TimeStampField);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="relationRuleNode"></param>
        /// <returns></returns>
        public override RuleBase Read(XmlNode relationRuleNode)
        {
            EntityRelationRule rule = new EntityRelationRule(
                string.Empty, string.Empty, EntityType.Grants, 
                EntityType.Publications, string.Empty);
            rule.RuleName = XmlDataUtil.GetAttributeValue(relationRuleNode, "RuleName", "");
            rule.RuleType =
                (RuleType) Enum.Parse(
                               typeof (RuleType),
                               XmlDataUtil.GetAttributeValue(
                               relationRuleNode, "RuleType", RuleType.Link.ToString()));
            rule.IconPath = XmlDataUtil.GetAttributeValue(relationRuleNode, "IconPath", "");
            rule.SrcDataFormat =
                (SetDataSourceType) Enum.Parse(
                                        typeof (SetDataSourceType), XmlDataUtil.GetAttributeValue(
                                                                        relationRuleNode, "SrcDataFormat",
                                                                        SetDataSourceType.XML.ToString()));
            rule.SrcDataFrom = (SampleDataSourceType) Enum.Parse(typeof (SampleDataSourceType),
                                                                 XmlDataUtil.GetAttributeValue(relationRuleNode,
                                                                                               "SrcDataFrom",
                                                                                               SampleDataSourceType.
                                                                                                   EntityDataSet.
                                                                                                   ToString()));
            rule.NetworkName = XmlDataUtil.GetAttributeValue(relationRuleNode, "NetworkName", "");
            rule.SrcEntityType =
                (EntityType)Enum.Parse(typeof(EntityType),
                    XmlDataUtil.GetAttributeValue(relationRuleNode, "SrcEntityType", EntityType.Grants.ToString()));
            rule.SrcKey = XmlDataUtil.GetAttributeValue(relationRuleNode, "SrcKey", "");
            rule.SrcEntitySetName = XmlDataUtil.GetAttributeValue(relationRuleNode, "SrcSetName", "");
            rule.Directional =
                bool.Parse(XmlDataUtil.GetAttributeValue(relationRuleNode, "Directional", false.ToString()));
            rule.LinkType = (LinkType) Enum.Parse(typeof (LinkType),
                                                  XmlDataUtil.GetAttributeValue(relationRuleNode, "LinkType",
                                                                                Networks.LinkType.Citation.ToString()));
            rule.TgtEntityType =
                (EntityType)Enum.Parse(typeof(EntityType),
                    XmlDataUtil.GetAttributeValue(relationRuleNode, "TgtEntityType", EntityType.Grants.ToString()));

            rule.DbProvider = (DataProviderType)Enum.Parse(
                                                     typeof(DataProviderType),
                                                     XmlDataUtil.GetAttributeValue(
                                                         relationRuleNode, "DbProvider",
                                                         DataProviderType.MSSQL.ToString()));
            rule.ConnStr = XmlDataUtil.GetAttributeValue(relationRuleNode, "ConnStr", "");
            rule.Sql = XmlDataUtil.GetAttributeValue(relationRuleNode, "Sql", "");
            rule.ParameterTypes = new Dictionary<string, SqlDbType>();

            rule.FieldNameMappings = new Dictionary<string, string>();
            XmlNodeList inputMappingNodes = relationRuleNode.SelectNodes("InputMappings/InputMapping");
            if (inputMappingNodes != null && inputMappingNodes.Count > 0)
            {
                foreach (XmlNode inputMappingNode in inputMappingNodes)
                {
                    string srcField = XmlDataUtil.GetAttributeValue(inputMappingNode, "SrcField", "");
                    string propName = XmlDataUtil.GetAttributeValue(inputMappingNode, "PropName", "");
                    rule.FieldNameMappings.Add(propName, srcField);
                }
            }

            rule.SqlParameters = new Dictionary<string, string>();
            XmlNodeList paramNodes = relationRuleNode.SelectNodes("SqlParameters/SqlParameter");
            if (paramNodes != null && paramNodes.Count > 0)
            {
                foreach (XmlNode paramNode in paramNodes)
                {
                    string propName = XmlDataUtil.GetAttributeValue(paramNode, "PropertyName", "");
                    string paramName = XmlDataUtil.GetAttributeValue(paramNode, "ParameterName", "");
                    rule.SqlParameters.Add(propName, paramName);
                }
            }

            rule.ParameterTypes = new Dictionary<string, SqlDbType>();
            XmlNodeList inputParamNodes = relationRuleNode.SelectNodes("ParameterTypes/InputParameter");
            if (inputParamNodes != null && inputParamNodes.Count > 0)
            {
                foreach (XmlNode inputParamNode in inputParamNodes)
                {
                    string srcField = XmlDataUtil.GetAttributeValue(inputParamNode, "ParameterName", "");
                    SqlDbType dbType = (SqlDbType)Enum.Parse(typeof(SqlDbType),
                        XmlDataUtil.GetAttributeValue(inputParamNode, "DataType", SqlDbType.VarChar.ToString()));
                    rule.ParameterTypes.Add(srcField, dbType);
                }
            }

            //rule.FieldTransformations = new Dictionary<string, string>();
            //XmlNodeList transformNodes = relationRuleNode.SelectNodes("FieldTransformations/FieldTransformation");
            //if (transformNodes != null && transformNodes.Count > 0)
            //{
            //    foreach (XmlNode transformNode in transformNodes)
            //    {
            //        string fieldName = XmlDataUtil.GetAttributeValue(transformNode, "FieldName", "");
            //        string code = XmlDataUtil.GetAttributeValue(transformNode, "Code", "");
            //        rule.FieldTransformations.Add(fieldName, code);
            //    }
            //}

            rule.OutputFieldNameMappings = new Dictionary<string, string>();
            XmlNodeList outputMappingNodes = relationRuleNode.SelectNodes("OutputMappings/OutputMapping");
            if (outputMappingNodes != null && outputMappingNodes.Count > 0)
            {
                foreach (XmlNode outputMappingNode in outputMappingNodes)
                {
                    string colName = XmlDataUtil.GetAttributeValue(outputMappingNode, "ColName", "");
                    string tgtField = XmlDataUtil.GetAttributeValue(outputMappingNode, "TgtField", "");
                    rule.OutputFieldNameMappings.Add(colName, tgtField);
                }
            }

            rule.LinkCalcArgumentMappings = new Dictionary<string, ArgumentFieldBinding>();
            XmlNodeList argMappingNodes = relationRuleNode.SelectNodes("LinkCalcArgMappings/LinkCalcArgMapping");
            if (argMappingNodes != null && argMappingNodes.Count > 0)
            {
                foreach (XmlNode argMappingNode in argMappingNodes)
                {
                    string argName = XmlDataUtil.GetAttributeValue(argMappingNode, "ArgName", "");
                    string propName = XmlDataUtil.GetAttributeValue(argMappingNode, "FieldName", "");
                    bool fromSrcEntity =
                        bool.Parse(XmlDataUtil.GetAttributeValue(argMappingNode, "FromSrcEntity", false.ToString()));
                    bool fromTgtEntity =
                        bool.Parse(XmlDataUtil.GetAttributeValue(argMappingNode, "FromTgtEntity", true.ToString()));
                    ArgumentFieldBinding argBinding = new ArgumentFieldBinding();
                    argBinding.ArgumentName = argName;
                    argBinding.PropertyName = propName;
                    argBinding.FromSrcEntity = fromSrcEntity;
                    argBinding.FromTgtEntity = fromTgtEntity;
                    rule.LinkCalcArgumentMappings.Add(argName, argBinding);
                }
            }

            rule.EntityLinkerName =
                XmlDataUtil.GetAttributeValue(relationRuleNode, "EntityLinkerName", "");
            rule.LinkDistanceThreshold = double.Parse(
                XmlDataUtil.GetAttributeValue(relationRuleNode, "LinkDistanceThreshold", "1"));
            rule.AllowLoopBack = bool.Parse(
                XmlDataUtil.GetAttributeValue(relationRuleNode, "AllowLoopBack", false.ToString()));
            rule.HopDampFactor = double.Parse(
                XmlDataUtil.GetAttributeValue(relationRuleNode, "HopDampFactor", "0.5"));
            rule.TimeStampField = XmlDataUtil.GetAttributeValue(relationRuleNode, "TimeStampField", "");

            //rule.DedupCalculatorType = assembly.GetType(
            //    XmlDataUtil.GetAttributeValue(relationRuleNode, "DedupCalcType", ""));
            //rule.DedupNativeComparers = new Dictionary<string, string>();
            //XmlNodeList nativeNodes = relationRuleNode.SelectNodes("NativeComparers/NativeComparer");
            //if (nativeNodes != null && nativeNodes.Count > 0)
            //{
            //    foreach (XmlNode nativeNode in nativeNodes)
            //    {
            //        string fieldName = XmlDataUtil.GetAttributeValue(nativeNode, "FieldName", "");
            //        string comparerName = XmlDataUtil.GetAttributeValue(nativeNode, "Comparer", "");
            //        rule.DedupNativeComparers.Add(fieldName, comparerName);
            //    }
            //}
            //rule.DedupAssociativeComparers = new Dictionary<string, string>();
            //XmlNodeList assoNodes = relationRuleNode.SelectNodes("AssociativeComparers/AssociativeComparer");
            //if (assoNodes != null && assoNodes.Count > 0)
            //{
            //    foreach (XmlNode associativeNode in assoNodes)
            //    {
            //        string fieldName = XmlDataUtil.GetAttributeValue(associativeNode, "FieldName", "");
            //        string comparerName = XmlDataUtil.GetAttributeValue(associativeNode, "Comparer", "");
            //        rule.DedupAssociativeComparers.Add(fieldName, comparerName);
            //    }
            //}
            //rule.DedupFieldWeights = new Dictionary<string, double>();
            //XmlNodeList fieldWeightNodes = relationRuleNode.SelectNodes("DedupFieldWeights/Field");
            //if (fieldWeightNodes != null && fieldWeightNodes.Count > 0)
            //{
            //    foreach (XmlNode fieldNode in fieldWeightNodes)
            //    {
            //        string fieldName = XmlDataUtil.GetAttributeValue(fieldNode, "FieldName", "");
            //        double weight = double.Parse(XmlDataUtil.GetAttributeValue(fieldNode, "Weight", "1"));
            //        rule.DedupFieldWeights.Add(fieldName, weight);
            //    }
            //}
            //rule.DedupPenalties = new Dictionary<string, double>();
            //XmlNodeList penaltyNodes = relationRuleNode.SelectNodes("Penalties/Penalty");
            //if (penaltyNodes != null && penaltyNodes.Count > 0)
            //{
            //    foreach (XmlNode penaltyNode in penaltyNodes)
            //    {
            //        string fieldName = XmlDataUtil.GetAttributeValue(penaltyNode, "FieldName", "");
            //        double penalty = double.Parse(XmlDataUtil.GetAttributeValue(penaltyNode, "Penalty", "0"));
            //        rule.DedupPenalties.Add(fieldName, penalty);
            //    }
            //}

            //rule.DedupAssociationThreshold = double.Parse(
            //    XmlDataUtil.GetAttributeValue(relationRuleNode, "DedupAssociationThreshold", "0"));
            //rule.DedupSimilarityThreshold = double.Parse(
            //    XmlDataUtil.GetAttributeValue(relationRuleNode, "DedupSimilarityThreshold", "1"));


            return rule;
        }
        #endregion
    }
}
